﻿using Common.Models;
using Common.Utils;
using FileServer.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Net;

namespace FileServer.Controllers
{
    /// <summary>
    /// 文件操作控制器
    /// </summary>
    /// <remarks>
    /// 提供文件上传、下载、列表获取等功能的API接口
    /// </remarks>
    [Route("api/[controller]")]
    [ApiController]
    [RequestSizeLimit(ConfigHelper.MaxFileSize)]
    public class FileController : ControllerBase
    {
        private readonly string _fileDirectory;
        private readonly ILogger<FileController> _logger;

        /// <summary>
        /// 初始化文件控制器
        /// </summary>
        /// <param name="logger">日志记录器</param>
        /// <param name="configuration">配置对象</param>
        public FileController(ILogger<FileController> logger, IConfiguration configuration)
        {
            _logger = logger;
            _fileDirectory = configuration["FileDirectory"] ?? Path.Combine(Directory.GetCurrentDirectory(), "Files");

            // 确保文件目录存在
            if (!Directory.Exists(_fileDirectory))
            {
                Directory.CreateDirectory(_fileDirectory);
            }
        }

        /// <summary>
        /// 获取文件列表
        /// </summary>
        [HttpGet("list")]
        public IActionResult GetFileList()
        {
            try
            {
                DirectoryInfo directoryInfo = new DirectoryInfo(_fileDirectory);

                if (!directoryInfo.Exists)
                {
                    _logger.LogWarning("请求的目录不存在: {Directory}", _fileDirectory);
                    return NotFound("目录不存在");
                }

                List<FileData> files = directoryInfo.GetFiles()
                    .Select(fileInfo => new FileData()
                    {
                        Name = fileInfo.Name,
                        Size = fileInfo.Length,
                        LastModified = fileInfo.LastWriteTime,
                        Path = fileInfo.FullName
                    })
                    .OrderByDescending(file => file.LastModified)
                    .ToList();

                return Ok(files);
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.LogError(ex, "无权访问目录或文件: {Directory}", _fileDirectory);
                return StatusCode(500, "无权访问目录或文件");
            }
            catch (IOException ex)
            {
                _logger.LogError(ex, "读取目录时发生IO错误: {Directory}", _fileDirectory);
                return StatusCode(500, "读取目录时发生IO错误");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文件列表失败: {Directory}", _fileDirectory);
                return StatusCode(500, "获取文件列表失败");
            }
        }

        /// <summary>
        /// 获取文件信息
        /// </summary>
        [HttpGet("info/{fileName}")]
        public IActionResult GetFileInfo(string fileName)
        {
            try
            {
                var filePath = Path.Combine(_fileDirectory, fileName);
                if (!System.IO.File.Exists(filePath))
                {
                    return NotFound($"文件 {fileName} 不存在");
                }

                var fileInfo = new FileInfo(filePath);
                var fileData = new FileData()
                {
                    Name = fileName,
                    Size = fileInfo.Length,
                    LastModified = fileInfo.LastWriteTime,
                    Extension = fileInfo.Extension
                };

                return Ok(fileData);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取文件信息失败");
                return StatusCode(500, "获取文件信息失败");
            }
        }

        /// <summary>
        /// 下载文件（支持断点续传）
        /// </summary>
        [HttpGet("download/{fileName}")]
        public IActionResult DownloadFile(string fileName)
        {
            try
            {
                var filePath = Path.Combine(_fileDirectory, fileName);
                if (!System.IO.File.Exists(filePath))
                {
                    return NotFound($"文件 {fileName} 不存在");
                }

                var fileInfo = new FileInfo(filePath);
                var fileLength = fileInfo.Length;

                // 获取Range头，支持断点续传
                var rangeHeader = Request.Headers["Range"].ToString();
                long start = 0;
                long end = fileLength - 1;

                if (!string.IsNullOrEmpty(rangeHeader) && rangeHeader.StartsWith("bytes="))
                {
                    var range = rangeHeader.Substring(6);
                    var parts = range.Split('-');

                    if (parts.Length == 2)
                    {
                        if (long.TryParse(parts[0], out var startValue))
                        {
                            start = startValue;
                        }

                        if (long.TryParse(parts[1], out var endValue) && endValue > 0)
                        {
                            end = endValue;
                        }
                        else
                        {
                            end = fileLength - 1;
                        }
                    }
                }

                // 验证范围
                if (start >= fileLength || end >= fileLength || start > end)
                {
                    _logger.LogWarning($"无效的Range请求: {rangeHeader}, 文件大小: {fileLength}, 请求范围: {start}-{end}");
                    return BadRequest("无效的Range请求");
                }

                var contentLength = end - start + 1;

                // 使用更大的缓冲区提高传输效率
                var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, ConfigHelper.BufferSize);
                stream.Seek(start, SeekOrigin.Begin);

                // 设置响应头
                Response.Headers["Accept-Ranges"] = "bytes";
                Response.Headers["Content-Length"] = contentLength.ToString();
                Response.Headers["Content-Disposition"] = "attachment";
                Response.Headers["Last-Modified"] = fileInfo.LastWriteTimeUtc.ToString("R");
                Response.Headers["Cache-Control"] = "no-cache";
                Response.Headers["Pragma"] = "no-cache";

                // 设置状态码和Content-Range头
                if (start > 0 || end < fileLength - 1)
                {
                    // 部分内容响应
                    Response.StatusCode = 206; // Partial Content
                    Response.Headers["Content-Range"] = $"bytes {start}-{end}/{fileLength}";
                    _logger.LogInformation($"部分内容响应: {fileName}, 范围: {start}-{end}, 大小: {contentLength}");
                }
                else
                {
                    // 完整文件响应
                    Response.StatusCode = 200; // OK
                    Response.Headers["Content-Range"] = $"bytes 0-{fileLength - 1}/{fileLength}";
                    _logger.LogInformation($"完整文件响应: {fileName}, 大小: {contentLength}");
                }

                // 使用自定义的FileStreamResult以确保流正确关闭
                return new FileStreamResult(stream, "application/octet-stream")
                {
                    EnableRangeProcessing = true
                };
            }
            catch (FileNotFoundException)
            {
                _logger.LogWarning($"文件不存在: {fileName}");
                return NotFound($"文件 {fileName} 不存在");
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.LogError(ex, $"无权访问文件: {fileName}");
                return StatusCode(500, "无权访问文件");
            }
            catch (IOException ex)
            {
                _logger.LogError(ex, $"读取文件时发生IO错误: {fileName}");
                return StatusCode(500, "读取文件时发生IO错误");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"下载文件失败: {fileName}");
                return StatusCode(500, "下载文件失败");
            }
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        [HttpPost("upload")]
        public async Task<IActionResult> UploadFile(IFormFile file)
        {
            try
            {
                _logger.LogInformation($"开始处理文件上传请求");

                if (file == null)
                {
                    _logger.LogWarning("上传的文件为空");
                    return BadRequest("请选择要上传的文件");
                }

                if (file.Length == 0)
                {
                    _logger.LogWarning("上传的文件大小为0");
                    return BadRequest("文件不能为空");
                }

                _logger.LogInformation($"文件信息: 名称={file.FileName}, 大小={file.Length} 字节");

                if (file.Length > ConfigHelper.MaxFileSize)
                {
                    _logger.LogWarning($"文件大小超过限制: {file.Length} > {ConfigHelper.MaxFileSize}");
                    return BadRequest($"文件大小超过限制: {ConfigHelper.MaxFileSize / (1024 * 1024 * 1024)}GB");
                }

                // 检查磁盘空间
                var fullPath = Path.GetFullPath(_fileDirectory);
                var rootPath = Path.GetPathRoot(fullPath);
                if (!string.IsNullOrEmpty(rootPath))
                {
                    var driveInfo = new DriveInfo(rootPath);
                    if (driveInfo.AvailableFreeSpace < file.Length)
                    {
                        _logger.LogError($"磁盘空间不足: 需要 {file.Length} 字节，可用 {driveInfo.AvailableFreeSpace} 字节");
                        return StatusCode(507, "磁盘空间不足");
                    }
                }

                var fileName = Path.GetFileName(file.FileName);
                if (string.IsNullOrEmpty(fileName))
                {
                    _logger.LogWarning("文件名无效");
                    return BadRequest("文件名无效");
                }

                var filePath = Path.Combine(_fileDirectory, fileName);

                // 如果文件已存在，添加时间戳
                if (System.IO.File.Exists(filePath))
                {
                    var nameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
                    var ext = Path.GetExtension(fileName);
                    var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
                    fileName = $"{nameWithoutExt}_{timestamp}{ext}";
                    filePath = Path.Combine(_fileDirectory, fileName);
                    _logger.LogInformation($"文件已存在，重命名为: {fileName}");
                }

                _logger.LogInformation($"开始保存文件到: {filePath}");

                using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, ConfigHelper.BufferSize))
                {
                    await file.CopyToAsync(stream);
                }

                _logger.LogInformation($"文件上传成功: {fileName}, 大小: {file.Length} 字节, 路径: {filePath}");

                return Ok(new UploadMessage()
                {
                    Message = "文件上传成功",
                    FileName = fileName,
                    Size = file.Length
                });
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.LogError(ex, "无权访问文件目录");
                return StatusCode(500, "无权访问文件目录");
            }
            catch (IOException ex)
            {
                _logger.LogError(ex, "文件IO操作失败");
                return StatusCode(500, "文件IO操作失败");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件上传失败");
                return StatusCode(500, "文件上传失败");
            }
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        [HttpDelete("delete/{fileName}")]
        public IActionResult DeleteFile(string fileName)
        {
            try
            {
                _logger.LogInformation($"开始处理文件删除请求: {fileName}");

                if (string.IsNullOrEmpty(fileName))
                {
                    _logger.LogWarning("文件名不能为空");
                    return BadRequest("文件名不能为空");
                }

                var filePath = Path.Combine(_fileDirectory, fileName);

                if (!System.IO.File.Exists(filePath))
                {
                    _logger.LogWarning($"文件不存在: {fileName}");
                    return NotFound($"文件 {fileName} 不存在");
                }

                // 获取文件信息用于日志记录
                var fileInfo = new FileInfo(filePath);
                var fileSize = fileInfo.Length;

                // 删除文件
                System.IO.File.Delete(filePath);

                _logger.LogInformation($"文件删除成功: {fileName}, 大小: {fileSize} 字节");

                return Ok(new
                {
                    Message = "文件删除成功",
                    FileName = fileName,
                    Size = fileSize
                });
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.LogError(ex, $"无权删除文件: {fileName}");
                return StatusCode(500, "无权删除文件");
            }
            catch (IOException ex)
            {
                _logger.LogError(ex, $"删除文件时发生IO错误: {fileName}");
                return StatusCode(500, "删除文件时发生IO错误");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"删除文件失败: {fileName}");
                return StatusCode(500, "删除文件失败");
            }
        }
    }
}
